//自定义函数：
// 2019-9-02 刘鑫
//2019-9-05 谭黎明
//2019-9-07 蒲瞻星
//2019-9-10 蒲瞻星

// 三维辅助工具：
// 1.主显示区的坐标系，2，右上角显示区的视角指示器，3，拉伸，旋转的法线。


import {ArrowHelper,Vector3,Group,SphereBufferGeometry,MeshPhongMaterial,Mesh,Line,
    GridHelper, PlaneBufferGeometry, MeshBasicMaterial, MeshLambertMaterial,DoubleSide, MeshStandardMaterial, CanvasTexture, FontLoader,
    TextBufferGeometry} from "./three.module.js";
import {BoxBufferGeometry} from "./three.module.js";
import {EdgesGeometry, LineSegments} from "./three.module.js";
import {LineBasicMaterial} from "./three.module.js";
import {Object3D} from "./three.module.js";
import {BufferGeometry, CylinderBufferGeometry,Float32BufferAttribute} from "./three.module.js";

var objectMainAxes;
var objectMainAxes_Arrow;
var helper_Line;
var selected_arrow;
var gridHelper_xoy;
var gridHelper_xoz;
var gridHelper_yoz;
var arrowBefore=null;
var arrowAfter=null;
var length_for_helper;


function mainAxes_Arrow(length) {
    length_for_helper=length;

    objectMainAxes_Arrow=new Object3D();

    //主坐标轴***************************************************************

    var gizmoMaterial = new MeshBasicMaterial( {
        depthTest: false,
        depthWrite: false,
        transparent: true,
        side: DoubleSide,
        fog: false
    } );

    var gizmoLineMaterial = new LineBasicMaterial( {
        depthTest: false,
        depthWrite: false,
        transparent: true,
        linewidth: 1,
        fog: false
    } );
    //********           原来的辅助箭头的颜色                       ********
    var matRed = gizmoMaterial.clone();
    matRed.color.set( 0xff0000 );

    var matGreen = gizmoMaterial.clone();
    matGreen.color.set( 0x00ff00 );

    var matBlue = gizmoMaterial.clone();
    matBlue.color.set( 0x0000ff );
    //*******           原来的线的的颜色                        ********
    var matLineRed = gizmoLineMaterial.clone();
    matLineRed.color.set( 0xff0000 );

    var matLineGreen = gizmoLineMaterial.clone();
    matLineGreen.color.set( 0x00ff00 );

    var matLineBlue = gizmoLineMaterial.clone();
    matLineBlue.color.set( 0x0000ff );
    //********                                  *********

    //****************触碰到后的辅助箭头********************
    var matInvisible = gizmoMaterial.clone();
    // matInvisible.color.set(0xFFD700);
    matInvisible.opacity = 0.33;
    var matHelper_red = gizmoMaterial.clone();
    matHelper_red.opacity = 0.33;
    matHelper_red.color.set(0x000000);
    //****************触碰到后的辅助箭头********************

    // for CylinderBufferGeometry
    // radiusTop 	可选。此属性定义圆柱体顶部圆半径。默认值是 20
    // radiusBottom 	可选。此属性定义圆柱体底部圆半径。默认值是 20
    // height 	可选。此属性定义圆柱体的高度。默认值是 100
    // radiusSegments 	可选。此属性定义圆柱体的上下部的圆截面分成多少段。默认值是 8
    // heightSegments 	可选。此属性定义圆柱体竖直方向上分成多少段。默认值是 1
    // openEnded 	可选。此属性定义圆柱体的顶部和底部是否为打开。默认值是 false
    var arrowGeometry=new CylinderBufferGeometry(0, 0.02, 0.07, 12, 1, false );

    var lineGeometry = new BufferGeometry( );
    lineGeometry.addAttribute( 'position', new Float32BufferAttribute( [ 0, 0, 0,	1, 0, 0 ], 3 ) );
    arrowBefore={
        X: [
            [ new Mesh( arrowGeometry, matRed ), [ 1, 0, 0 ], [ 0, 0, - Math.PI / 2 ], null, 'fwd' ],
            //  [ new Mesh( arrowGeometry, matRed ), [ 1, 0, 0 ], [ 0, 0, Math.PI / 2 ], null, 'bwd' ],
            [ new Line( lineGeometry, matLineRed ) ]
        ],
        Y: [
            [ new Mesh( arrowGeometry, matGreen ), [ 0, 1, 0 ], null, null, 'fwd' ],
            //   [ new Mesh( arrowGeometry, matGreen ), [ 0, 1, 0 ], [ Math.PI, 0, 0 ], null, 'bwd' ],
            [ new Line( lineGeometry, matLineGreen ), null, [ 0, 0, Math.PI / 2 ]]
        ],
        Z: [
            [ new Mesh( arrowGeometry, matBlue ), [ 0, 0, 1 ], [ Math.PI / 2, 0, 0 ], null, 'fwd' ],
            //    [ new Mesh( arrowGeometry, matBlue ), [ 0, 0, 1 ], [ - Math.PI / 2, 0, 0 ], null, 'bwd' ],
            [ new Line( lineGeometry, matLineBlue ), null, [ 0, - Math.PI / 2, 0 ]]
        ]
    };

    arrowAfter={
        X: [
            [ new Mesh( new CylinderBufferGeometry(0, 0.02, 0.07, 12, 1, false ), matInvisible ), [ 1, 0, 0 ], [ 0, 0, - Math.PI / 2 ]],
            [ new Line( lineGeometry, matHelper_red.clone() ), [ - 1e3, 0, 0 ], null, [ 1e6, 1, 1 ], 'helper' ]
        ],
        Y: [
            [ new Mesh( new CylinderBufferGeometry( 0, 0.02, 0.07, 12, 1, false ), matInvisible ), [ 0, 1, 0 ]],
            [ new Line( lineGeometry, matHelper_red.clone() ), [ 0, - 1e3, 0 ], [ 0, 0, Math.PI / 2 ], [ 1e6, 1, 1 ], 'helper' ]
        ],
        Z: [
            [ new Mesh( new CylinderBufferGeometry( 0, 0.02, 0.07, 12, 1, false ), matInvisible ), [ 0, 0, 1 ], [ Math.PI / 2, 0, 0 ]],
            [ new Line( lineGeometry, matHelper_red.clone() ), [ 0, 0, - 1e3 ], [ 0, - Math.PI / 2, 0 ], [ 1e6, 1, 1 ], 'helper' ]
        ]
    };
    //主坐标轴***************************************************************
    setupGizmo(arrowBefore,'X',length,true);
    setupGizmo(arrowBefore,'Y',length,true);
    setupGizmo(arrowBefore,'Z',length,true);
    return objectMainAxes_Arrow;
}

//**************************************对坐标轴中的辅助箭头的增删操作的函数**********************************
function setupGizmo( gizmoMap,name,length,add) {    //第一个参数表示坐标系是前还是后，第二个表示修改的辅助箭头，第三个true表示增加，false表示删除
    if(add===false){
        objectMainAxes_Arrow.remove(selected_arrow,helper_Line);
        return;
    }
    for ( var i = gizmoMap[ name ].length-1;i>=0 ; i-- ) {
        var object = gizmoMap[name][i][0].clone();
        var position = gizmoMap[name][i][1];
        var rotation = gizmoMap[name][i][2];
        var scale = gizmoMap[name][i][3];
        var tag = gizmoMap[name][i][4];
        // name and tag properties are essential for picking and updating logic.
        object.name = name;
        object.tag = tag;
        if (position) {
            object.position.set(position[0], position[1], position[2]);
        }
        if (rotation) {
            object.rotation.set(rotation[0], rotation[1], rotation[2])
        }
        if (scale) {
            object.scale.set(scale[0], scale[1], scale[2]);
        }
        object.updateMatrix();
        var tempGeometry = object.geometry.clone();
        tempGeometry.applyMatrix(object.matrix);
        object.geometry = tempGeometry;
        object.renderOrder = Infinity;
        object.position.set(0, 0, 0);
        object.rotation.set(0, 0, 0);
        object.scale.set(length, length, length);   //箭头辅助的设置长短
        if(gizmoMap===arrowAfter){
            if(i===1){
                helper_Line=object;
            }
            else {
                selected_arrow = object;            //如果添加的是选中后的效果，吧选中的效果保留，方便后面的删除
            }
        }
        objectMainAxes_Arrow.add(object);
    }
}
//**************************************对坐标轴中的辅助箭头的增删操作的函数**********************************

//文件外修改坐标系辅助箭头的函数
function arrow_change(which,choice){
    setupGizmo(arrowAfter, which, length_for_helper, choice);
}




//1.mainAxes代表的是 建模初始启动主显示区中的坐标系
function mainAxes(length) {

    //在外面加载字体
    var json = (function () {
        var json = null;
        $.ajax({
            'async': false,
            'global': false,
            'url': "./fonts/./helvetiker_regular.typeface.json",
            'dataType': "json",
            'success': function (data) {
                json = data;
            }
        });
        return json;
    })();

    var loader = new FontLoader();
    var fontTemp = loader.parse(json);

    objectMainAxes = new Object3D();
    //坐标原点
    var sphere = new SphereBufferGeometry(length * 0.02, 32, 32);
    var sphere_material = new MeshPhongMaterial({ color: 0xffffff });
    var origin = new Mesh(sphere, sphere_material);


    //xoy面,xoz,yoz面
    var sideLength = length * 0.4;
    var plane = new PlaneBufferGeometry(sideLength, sideLength);
    var XOYmaterial = new MeshLambertMaterial({ color: 0xbcee68, side: DoubleSide, transparent: true, opacity: 0.5 });
    var XOZmaterial = new MeshLambertMaterial({ color: 0xFF8C69, side: DoubleSide, transparent: true, opacity: 0.5 });
    var YOZmaterial = new MeshLambertMaterial({ color: 0xb0e2ff, side: DoubleSide, transparent: true, opacity: 0.5 });

    //xoy面
    var planeXOY = new Mesh(plane, XOYmaterial);
    planeXOY.translateX(sideLength * 0.5);
    planeXOY.translateY(sideLength * 0.5);
    planeXOY.name='xoy';

    //xoz面
    var planeXOZ = new Mesh(plane, XOZmaterial);
    planeXOZ.translateX(sideLength * 0.5);
    planeXOZ.rotation.set(Math.PI / 2, 0, 0);
    planeXOZ.translateY(sideLength * 0.5);
    planeXOZ.name='xoz';

    //yoz面
    var planeYOZ = new Mesh(plane, YOZmaterial);
    planeYOZ.translateY(sideLength * 0.5);
    planeYOZ.rotation.set(0, Math.PI / 2, 0);
    planeYOZ.translateX(-sideLength * 0.5);
    planeYOZ.name='yoz';

    //显示坐标面名称
    //创建法向量材质
    var meshMaterialNum = new MeshBasicMaterial({
        color: 0x000000
    });
    var geometryXOY = new TextBufferGeometry('XOY面', {
        font: fontTemp,
        size: length/20,
        height: 0
    });
    var geometryXOZ = new TextBufferGeometry('XOZ面', {
        font: fontTemp,
        size: length / 20,
        height: 0
    });
    var geometryYOZ = new TextBufferGeometry('YOZ面', {
        font: fontTemp,
        size: length / 20,
        height: 0
    });
    geometryXOY.rotateZ(Math.PI / 2);  //显示后将几何体旋转一下
    geometryXOZ.rotateY(Math.PI);
    geometryYOZ.rotateZ(Math.PI / 2);

    var meshXOY = new Mesh(geometryXOY, meshMaterialNum);
    var meshXOZ = new Mesh(geometryXOZ, meshMaterialNum);
    var meshYOZ = new Mesh(geometryYOZ, meshMaterialNum);

    //加在面上的字体
    meshXOY.translateX(10);
    meshXOY.translateY(3);
    meshXOZ.translateX(10);
    meshXOZ.translateY(8);
    meshYOZ.translateY(4);
    meshYOZ.translateX(-8);



    //网格面xoy
    gridHelper_xoy = new GridHelper(length * 1.4, 10);
    gridHelper_xoy.rotateX(Math.PI / 2);

    //网格面xoz
    gridHelper_xoz = new GridHelper(length * 1.4, 10);

    //网格面yoz
    gridHelper_yoz = new GridHelper(length * 1.4, 10);
    gridHelper_yoz.rotateZ(Math.PI/2);


    // group.add(origin, arrowX, arrowY, arrowZ, gridHelper, planeXOY, planeXOZ, planeYOZ);
    planeXOY.add(meshXOY);
    planeXOZ.add(meshXOZ);
    planeYOZ.add(meshYOZ);

    objectMainAxes.add(origin, gridHelper_xoy);
    // group.add(planeXOY, planeXOZ, planeYOZ);

    objectMainAxes.add(planeXOY, planeXOZ, planeYOZ);

    return objectMainAxes;
}

function grid_to_xoz() {
    objectMainAxes.remove(gridHelper_yoz,gridHelper_xoy);
    objectMainAxes.add(gridHelper_xoz);
}
function grid_to_xoy() {
    objectMainAxes.remove(gridHelper_yoz,gridHelper_xoz);
    objectMainAxes.add(gridHelper_xoy);
}
function grid_to_yoz() {
    objectMainAxes.remove(gridHelper_xoz,gridHelper_xoy);
    objectMainAxes.add(gridHelper_yoz);
}


//*************************************2.smallAxes代表的是右上角的坐标指示器。*******************************

function smallAxes(){


    var group=new Group();

    //正方体
    var a=15;
    var cubeGeo=new BoxBufferGeometry(a,a,a);


    //ctx.drawImage(front, 0, 0);
    var front = getTextCanvas('前');
    var ctxFront = front.getContext('2d');

    var right = getTextCanvas('右');
    var ctxRight = right.getContext('2d');

    // 未旋转
    // 旋转
    ctxFront.rotate(-Math.PI/2);
    //ctx.translate(0, a);
    // ctx.translate(0,a);
    ctxFront.drawImage(front, -500, -45);

    ctxRight.rotate(-Math.PI);
    ctxRight.drawImage(right, -500, -500);//-300-->-200 往下，

    var mats = [];
    mats.push(new MeshPhongMaterial({ color: 0xffffff, transparent: true, opacity: 1, map: new CanvasTexture(front) }));
    mats.push(new MeshPhongMaterial({ color: 0xffffff, transparent: true, opacity: 1, map: new CanvasTexture(getTextCanvas('后')) }));
    mats.push(new MeshPhongMaterial({ color: 0xffffff, transparent: true, opacity: 1, map: new CanvasTexture(right) }));
    mats.push(new MeshPhongMaterial({color:0xffffff,transparent:true,opacity:1,map: new CanvasTexture(getTextCanvas('左'))}));
    mats.push(new MeshPhongMaterial({color:0xffffff,transparent:true,opacity:1,map: new CanvasTexture(getTextCanvas('上'))}));
    mats.push(new MeshPhongMaterial({ color: 0xffffff, transparent: true, opacity: 1, map: new CanvasTexture(getTextCanvas('下')) }));


    var edges = new EdgesGeometry(cubeGeo);

    var cube=new Mesh(cubeGeo,mats);
    var line = new LineSegments( edges, new LineBasicMaterial( { color: 0xffffff } ));



    cube.position.set(0,0,0);
    cube.castShadow=true;
    // sceneOrtho.add(cube);
    //

    // //添加箭头。。
    // // z轴，蓝色
    var arrow1=new ArrowHelper(new Vector3(0,0,1),new Vector3(-7.5,-7.5,-7.5),22,0X3333FF,1.2,1.2);
    // sceneOrtho.add(arrow1);
    //
    // //Y轴，绿色
    var arrow2=new ArrowHelper(new Vector3(0,1,0),new Vector3(-7.5,-7.5,-7.5),22,0X33FF33,1.2,1.2);
    // sceneOrtho.add(arrow2);
    // //x轴，红色
    var arrow3=new ArrowHelper(new Vector3(1,0,0),new Vector3(-7.5,-7.5,-7.5),22,0XFF3333,1.2,1.2);
    // sceneOrtho.add(arrow3);

    group.add(cube,line,arrow1,arrow2,arrow3);
    return group;
}


//此函数为smallAxes中调用的函数，为面贴文字图。
function getTextCanvas(text) {
    var width = 512, height = 512;
    var canvas = document.createElement('canvas');
    canvas.width = width;
    canvas.height = height;

    var ctx = canvas.getContext('2d');
    ctx.fillStyle = '#00ffff';
    ctx.fillRect(0, 0, width, height);

    ctx.font = 150 + 'px " bold';
    ctx.fillStyle = '#000000';
    ctx.textAlign = 'center';
    ctx.textBaseline = 'middle';
    ctx.fillText(text, width / 2, height / 2);
    return canvas;

}

export {mainAxes,smallAxes,mainAxes_Arrow}
export {grid_to_yoz,grid_to_xoz,grid_to_xoy}
export {arrow_change}